﻿#pragma once

#include <cstring>
#include <iostream>
#include <list>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>

namespace xy
{

namespace utils
{

namespace details
{

class data_stream;

}

class serializable
{
  public:
    /**
     * @brief 序列化接口
     *
     * @param[in] stream
     */
    virtual std::unique_ptr<details::data_stream> serialize() const = 0;

    /**
     * @brief  反序列化接口
     *
     * @param[in] stream
     * @return true
     * @return false
     */
    virtual bool deserialize(std::shared_ptr<details::data_stream> stream) = 0;
};

// 序列化宏
#define SERIALIZE(...)                                                                                                 \
    std::unique_ptr<xy::utils::details::data_stream> serialize() const override                                        \
    {                                                                                                                  \
        auto stream = std::make_unique<xy::utils::details::data_stream>();                                             \
        char type = xy::utils::details::data_stream::Custom;                                                           \
        stream->write((char *)&type, sizeof(char));                                                                    \
        stream->write_args(__VA_ARGS__);                                                                               \
        return stream;                                                                                                 \
    }                                                                                                                  \
    bool deserialize(std::shared_ptr<xy::utils::details::data_stream> stream) override                                 \
    {                                                                                                                  \
        char type;                                                                                                     \
        stream->read(&type, sizeof(char));                                                                             \
        if (type != xy::utils::details::data_stream::Custom)                                                           \
            return false;                                                                                              \
        return stream->read_args(__VA_ARGS__);                                                                         \
    }

namespace details
{

class data_stream
{
  public:
    // 序列化类型
    enum DataType
    {
        Bool,
        Char,
        Int32,
        Int64,
        Float,
        Double,
        String,
        Vector,
        List,
        Map,
        Set,
        Custom
    };

    // 内存端序
    enum ByteOrder
    {
        Big_Endian,
        Little_Endian
    };

    /**
     * @brief 空构造
     *
     */
    data_stream() : m_pos(0)
    {
        // 检测内存端序
        _check_byte_order();
    }

    data_stream(data_stream &&other) = delete;

    /**
     * @brief 输出结构
     *
     * @param[in] os
     * @param[in] stream
     * @return std::ostream&
     */
    friend std::ostream &operator<<(std::ostream &os, std::shared_ptr<data_stream> stream)
    {
        std::size_t size = stream->m_buf.size();
        // os << "data_stream size: " << size << std::endl;
        os << "data_stream content: {" << std::endl;

        std::size_t i = 0;
        while (i < size)
        {
            switch ((DataType)stream->m_buf[i])
            {
            case DataType::Bool: {
                if ((int)stream->m_buf[++i] == 0)
                    os << "false";
                else
                    os << "true";
                os << " -> boolean" << std::endl;
                ++i;
                break;
            }
            case DataType::Char: {
                os << (char)stream->m_buf[++i] << " -> char" << std::endl;
                ++i;
                break;
            }
            case DataType::Int32: {
                os << *(int32_t *)&stream->m_buf[++i] << " -> int32" << std::endl;
                i += sizeof(int32_t);
                break;
            }
            case DataType::Int64: {
                os << *(int64_t *)&stream->m_buf[++i] << " -> int64" << std::endl;
                i += sizeof(int64_t);
                break;
            }
            case DataType::Float: {
                os << *(float *)&stream->m_buf[++i] << " -> float" << std::endl;
                i += sizeof(float);
                break;
            }
            case DataType::Double: {
                os << *(double *)&stream->m_buf[++i] << " -> double" << std::endl;
                i += sizeof(double);
                break;
            }
            case DataType::String: {
                if ((DataType)stream->m_buf[++i] == DataType::Int32)
                {
                    int len = *(int *)&stream->m_buf[++i];
                    i += sizeof(int);
                    os << std::string(&stream->m_buf[i], len) << " -> string" << std::endl;
                    i += len;
                }
                else
                    // 字符串编码错误
                    throw std::logic_error("Parse string error");

                break;
            }
            case DataType::Vector: {
                os << "Vector : ";
                ++i;
                break;
            }
            case DataType::List: {
                os << "List : ";
                ++i;
                break;
            }
            case DataType::Map: {
                os << "Map : ";
                ++i;
                break;
            }
            case DataType::Set: {
                os << "Set : ";
                ++i;
                break;
            }
            default: {
                os << "Custom : " << std::endl;
                ++i;
                break;
            }
            }
        }
        os << "}";

        return os;
    }

    /**
     * @brief 流式输入
     *
     * @tparam T
     */
    template <typename T>
        requires(std::is_fundamental_v<T> || std::is_convertible_v<T, const char *> ||
                 std::is_base_of_v<serializable, T>)
    data_stream &operator<<(const T &value)
    {
        write(value);
        return *this;
    }

    /**
     * @brief 复合类型流式输入
     *
     * @tparam T
     */
    template <typename T>
        requires(std::is_fundamental_v<typename T::value_type> || std::is_same_v<typename T::value_type, std::string> ||
                 std::is_convertible_v<typename T::value_type, const char *>)
    data_stream &operator<<(const T &value)
    {
        write(value);
        return *this;
    }

    /**
     * @brief map 流式输入
     *
     * @tparam T
     * @tparam U
     */
    template <typename T, typename U>
        requires((std::is_fundamental_v<T> || std::is_same_v<T, std::string> ||
                  std::is_convertible_v<T, const char *>) &&
                 (std::is_fundamental_v<U> || std::is_same_v<U, std::string> || std::is_convertible_v<U, const char *>))
    data_stream &operator<<(const std::map<T, U> &value)
    {
        write(value);
        return *this;
    }

    /**
     * @brief 流式输出
     *
     * @tparam T
     */
    template <typename T>
        requires(std::is_fundamental_v<T> || std::is_convertible_v<T, const char *> ||
                 std::is_base_of_v<serializable, T>)
    data_stream &operator>>(T &value)
    {
        read(value);
        return *this;
    }

    /**
     * @brief 复合类型流式输出
     *
     * @tparam T
     */
    template <typename T>
        requires(std::is_fundamental_v<typename T::value_type> || std::is_same_v<typename T::value_type, std::string> ||
                 std::is_convertible_v<typename T::value_type, const char *>)
    data_stream &operator>>(T &value)
    {
        read(value);
        return *this;
    }

    /**
     * @brief map 流式输出
     *
     * @tparam T
     * @tparam U
     */
    template <typename T, typename U>
        requires(std::is_fundamental_v<T> || std::is_convertible_v<T, const char *> ||
                 std::is_base_of_v<serializable, T>)
    data_stream &operator>>(std::map<T, U> &value)
    {
        read(value);
        return *this;
    }

    /**
     * @brief 读取字符串
     *
     * @param[in] value
     * @param[in] len
     * @return true
     * @return false
     */
    bool read(char *value, int len)
    {
        // 注意 read 函数不检查数据类型
        std::memcpy(value, &m_buf.at(m_pos), len);
        m_pos += len;
        return true;
    }

    /**
     * @brief 读取字符串
     *
     * @param[in] value
     * @return true
     * @return false
     */
    bool read(std::string &value)
    {
        if (m_buf.at(m_pos) != DataType::String)
            return false;

        DataType type = (DataType)m_buf.at(++m_pos);
        if (type == DataType::Int32)
        {
            int len = *(int *)&m_buf.at(++m_pos);
            m_pos += sizeof(int);
            value = std::string(&m_buf.at(m_pos), len);
            m_pos += len;
        }
        else
            // 字符串编码错误
            throw std::logic_error("Parse string error");

        return true;
    }

    /**
     * @brief 读取集合
     *
     * @tparam T
     * @param[in] value
     * @return true
     * @return false
     */
    template <typename T> bool read(std::set<T> &value)
    {
        if (m_buf.at(m_pos) != DataType::Set)
            return false;

        m_pos++;
        int size;
        read(size);
        for (int i = 0; i < size; ++i)
        {
            T v;
            read(v);
            value.insert(v);
        }
        return true;
    }

    /**
     * @brief 读取 map
     *
     * @tparam T
     * @tparam U
     * @param[in] value
     * @return true
     * @return false
     */
    template <typename T, typename U> bool read(std::map<T, U> &value)
    {
        if (m_buf.at(m_pos) != DataType::Map)
            return false;

        m_pos++;
        int size;
        read(size);
        for (int i = 0; i < size; ++i)
        {
            T key;
            read(key);
            U val;
            read(val);
            value[key] = val;
        }
        return true;
    }

    /**
     * @brief 多参数读取
     *
     * @tparam T
     * @tparam Args
     * @param[in] value
     * @param[in] args
     * @return true
     * @return false
     */
    template <typename T, typename... Args> bool read_args(T &value, Args &...args)
    {
        return read(value) && read_args(args...);
    }

    /**
     * @brief 空递归
     *
     * @return true
     * @return false
     */
    bool read_args()
    {
        return true;
    }

#ifndef DATASTREAM_READ
#define DATASTREAM_READ(T, U, value)                                                                                   \
    bool read(T &value)                                                                                                \
    {                                                                                                                  \
        if (m_buf.at(m_pos) != DataType::U)                                                                            \
            return false;                                                                                              \
        value = *(T *)&m_buf.at(++m_pos);                                                                              \
        m_pos += sizeof(T);                                                                                            \
        return true;                                                                                                   \
    }

    DATASTREAM_READ(bool, Bool, value)
    DATASTREAM_READ(char, Char, value)
    DATASTREAM_READ(int32_t, Int32, value)
    DATASTREAM_READ(int64_t, Int64, value)
    DATASTREAM_READ(float, Float, value)
    DATASTREAM_READ(double, Double, value)
#endif

#ifndef DATASTREAM_READ_ITERABLE
#define DATASTREAM_READ_ITERABLE(C, U, value)                                                                          \
    template <typename T> bool read(std::C<T> &value)                                                                  \
    {                                                                                                                  \
        if (m_buf.at(m_pos) != DataType::U)                                                                            \
            return false;                                                                                              \
        m_pos++;                                                                                                       \
        int size;                                                                                                      \
        read(size);                                                                                                    \
        value.clear();                                                                                                 \
        for (int i = 0; i < size; ++i)                                                                                 \
        {                                                                                                              \
            T v;                                                                                                       \
            read(v);                                                                                                   \
            value.push_back(v);                                                                                        \
        }                                                                                                              \
        return true;                                                                                                   \
    }

    DATASTREAM_READ_ITERABLE(vector, Vector, value)
    DATASTREAM_READ_ITERABLE(list, List, value)
#endif

    /**
     * @brief 写入字符串
     *
     * @param[in] data
     * @param[in] len
     */
    void write(const char *data, int len)
    {
        // 扩容
        _reserve(len);

        int size = m_buf.size();
        m_buf.resize(size + len); // 重新设置大小，进行初始化，否则无法写入数据
        std::memcpy(&m_buf[size], data, len);
    }

    /**
     * @brief 写入字符串
     *
     * @param[in] value
     */
    void write(const char *value)
    {
        char type = DataType::String;
        write((char *)&type, sizeof(char));

        // 写入字符串长度
        int len = strlen(value);
        write(len);

        // 写入字符串内容
        write(value, len);
    }

    /**
     * @brief 读取字符串
     *
     * @param[in] value
     */
    void write(const std::string &value)
    {
        // 直接使用 C 字符串写入法
        write(value.c_str());
    }

    /**
     * @brief 读取 map
     *
     * @tparam T
     * @tparam U
     * @param[in] value
     */
    template <typename T, typename U> void write(const std::map<T, U> &value)
    {
        char type = DataType::Map;
        write((char *)&type, sizeof(char));

        // 写入 map 大小
        write((int)value.size());

        // 写入 map 内容
        for (auto &&pair : value)
        {
            write(pair.first);
            write(pair.second);
        }
    }

    /**
     * @brief 多参数读取
     *
     * @tparam T
     * @tparam Args
     * @param[in] value
     * @param[in] args
     */
    template <typename T, typename... Args> void write_args(const T &value, const Args &...args)
    {
        write(value);
        write_args(args...);
    }

    /**
     * @brief 空递归
     *
     */
    void write_args()
    {
    }

#ifndef DATASTREAM_WRITE
#define DATASTREAM_WRITE(T, U, value)                                                                                  \
    void write(T value)                                                                                                \
    {                                                                                                                  \
        char type = DataType::U;                                                                                       \
        write((char *)&type, sizeof(char));                                                                            \
        write((char *)&value, sizeof(T));                                                                              \
    }

    DATASTREAM_WRITE(bool, Bool, value)
    DATASTREAM_WRITE(char, Char, value)
    DATASTREAM_WRITE(int32_t, Int32, value)
    DATASTREAM_WRITE(int64_t, Int64, value)
    DATASTREAM_WRITE(float, Float, value)
    DATASTREAM_WRITE(double, Double, value)
#endif

#ifndef DATASTREAM_WRITE_ITERABLE
#define DATASTREAM_WRITE_ITERABLE(C, U, value)                                                                         \
    template <typename T> void write(const std::C<T> &value)                                                           \
    {                                                                                                                  \
        char type = DataType::U;                                                                                       \
        write((char *)&type, sizeof(char));                                                                            \
        write((int)value.size());                                                                                      \
        for (auto &&v : value)                                                                                         \
            write(v);                                                                                                  \
    }

    DATASTREAM_WRITE_ITERABLE(vector, Vector, value)
    DATASTREAM_WRITE_ITERABLE(list, List, value)
    DATASTREAM_WRITE_ITERABLE(set, Set, value)
#endif

  private:
    /**
     * @brief 重新分配容量
     *
     * @param[in] len
     */
    void _reserve(int len)
    {
        int size = m_buf.size();
        int cap = m_buf.capacity();

        if (size + len > cap)
        {
            // 扩容
            while (size + len > cap)
            {
                if (cap == 0)
                    cap = 1;
                else
                    cap *= 2;
            }
            m_buf.reserve(cap);
        }
    }

    /**
     * @brief 检测内存端序
     *
     * @return ByteOrder
     */
    ByteOrder _check_byte_order()
    {
        int n = 0x12345678;
        char str[4];

        memcpy(str, &n, sizeof(int));

        // 大端将高位字节放在低地址，因此 12 放在 0 的位置
        if (str[0] == 0x12)
            m_byteOrder = Big_Endian;
        else
            m_byteOrder = Little_Endian;

        return m_byteOrder;
    }

  private:
    int m_pos;               // 读取位置
    std::vector<char> m_buf; // 序列化缓冲区
    ByteOrder m_byteOrder;   // 内存端序
};

} // namespace details

} // namespace utils

} // namespace xy
